<?php 
/**
 * Wordpress theme Admin Panel
 * 
 * @package       WP.OctoMS
 * @link          http://wp.octoms.com
 * @copyright     Copyright 2012, Valentino-Jivko Radosavlevici (http://valentino.radosavlevici.com)
 * @license       GPL v3.0 (http://www.gnu.org/licenses/gpl-3.0.txt)
 * 
 * Redistributions of files must retain the above copyright notice.
 * 
 */

	// Define the slug
	define('ADMINSLUG', basename(dirname(__FILE__)));
	
	// Calculate the title
	define('WP_OCTOMS_TITLE', ucwords(strtolower(str_replace(array('-','_'), ' ', ADMINSLUG))));
	
	/**
	 * Load the OctoMS PHP Framework files
	 */
	if (!function_exists('octoms_load'))
	{
		function octoms_load()
		{
			if (!defined('OCTOMS'))
			{	
				// Start the output buffer
				ob_start();
				
				/**
				 * Basic application information
				 */
				define('OCTOMS', '0.0.1');			# the framework version
				define('ROOT', dirname(__FILE__));	# the framework root
				define('APP_FOLDER', 'app');		# the application folder name (you may change this)
		
				/**
				 * Load the rest of the constants
				 */
				require_once ROOT.DIRECTORY_SEPARATOR.'core'.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'constants.inc';
				
				/**
				 * Load the bootstrap utility
				 */
				require_once CORE_LIB.DS.'octoms'.EXT;
			}
		}
		octoms_load();
	}
	
	// Don't overwrite this
	if (!function_exists('octoms_admin'))
	{
		// Deploy the OctoMS PHP Framework
		function octoms_admin()
		{			
			// Load controllers
			octoms::$oms_info['load_controller'] = true;
			
			// It's the new OctoMS!
			new octoms();
		
		}
		
		// The public version
		function octoms_public()
		{
			// Load controllers
			octoms::$oms_info['load_controller'] = false;

			// It's the new OctoMS!
			new octoms(false);
			
			// Append the shortcodes
			octoms('template',OMS_L)->_shortcodes();
			
			// Use the custom JS
			@wp_enqueue_script(
				'js/script.js',
				get_template_directory_uri().'/js/script.js',
				false,
				'1.0',
				true
			);
			
			// Create the WP-OctoMS Widget class
			class WP_OctoMS_Widget extends WP_Widget {

				// On extend, modify these two
				var $widgetClassName = null;
				var $widgetClassMethod = null;
				
				function _getWidgetDetails()
				{
					// The widget name and method are mandatory
					if (is_null($this->widgetClassName) || is_null($this->widgetClassMethod)) return false;
					
					// Initiate the reflection method
					$reflection = new ReflectionMethod('w_'.$this->widgetClassName, $this->widgetClassMethod);
					
					// Get the comments
					$c = trim(preg_replace('/[^\n]*?\*/', '', $reflection->getDocComment()),'/');
					
					// Prepare the regex
					$regex = '/@([a-zA-Z0-9_]*?)\s+([^\e]*?)(?=@|\Z)/m';
					
					// Set the description arguments
					global $widgetCustomArgs;
					$widgetCustomArgs = array();
					
					// Get the object itself
					$object = 'w_'.$this->widgetClassName;
					$object = new $object;
					
					// Is the helper defined?
					if (method_exists($object, '_h_'.$this->widgetClassMethod))
					{
						$widgetCustomArgs = @call_user_func(array($object,'_h_'.$this->widgetClassMethod));
					}

					// Replace set values
					$c = preg_replace_callback(
						'/\{([a-z0-9\_]*)\}/i',
						create_function(
							'$str',
							'global $widgetCustomArgs; 
							return 
								isset($widgetCustomArgs[$str[1]])
								?
								str_replace(\'@\',\'&#64;\',$widgetCustomArgs[$str[1]])
								:
								\'\';'
						), 
						$c
					);
					
					// Any match?
					if (preg_match_all($regex, $c, $reg))
					{
						// Get the description array
						$c = explode("\r\n", trim(preg_replace($regex, '', $c)));
						
						// Set the title
						$title = array_shift($c);
						
						// Set the description
						$description = implode("\r\n", $c);
						
						// New lines to breaks
						$description = nl2br($description);
						
						// Create the "clean" description
						$clean_description = strip_tags($description);
						
						// Prepare the parameters
						$params = array();
						
						// Show the "content" textarea?
						$content = false;
						
						// The new regular expression
						$regex2 = '/^\s*?([a-zA-Z\_]*)\s+?([a-zA-Z0-9\_$]*)\s*(.*)$/im';
						
						// Go through all of the parameters
						foreach ($reg[1] AS $key => $r)
						{
							if (trim(strtolower($r)) == 'param')
							{
								// Found one!
								if (preg_match($regex2, str_replace("\r\n", '', $reg[2][$key]), $m))
								{
									// Get the name
									$name = str_replace('$', '', $m[2]);
									
									// Get the type
									$type = $m[1];
									
									// Any description ?
									if (preg_match('/\[([^\]]*)\]/m', $m[3],$_m))
									{
										$m[3] = preg_replace('/\[([^\]]*)\]/m', '', $m[3]);
										$desc = $_m[1];
									}
									else 
									{
										$desc = ucfirst(str_replace('_', ' ', $name));
									}
									$desc = trim($desc,':');
									
									// The default value
									$default = trim($m[3]);
									$strict = false;

									// Is it a strict list?
									if(strpos($default, '<ul>') !== false)
									{
										// This is a strict list
										$strict = true;
										
										// Get all of the elements
										preg_match_all('%<li>([^<]*)</li>%m', $default, $li, PREG_PATTERN_ORDER);

										// Any results?
										if (count($li[1])>0)
										{
											$default = array();
											foreach ($li[1] AS $element)
											{
												if (strlen($element)>0)
												{
													$default[$element] = $element;
												}
											}
										}
									}
									else 
									{
										switch ($type)
										{
											case 'int':
												$default = intval($default);
												break;
											case 'float':
												$default = (float)$default;
												break;
											case 'numeric':
												$default = intval($default);
												break;
											case 'bool':
											case 'boolean':
												$default = in_array(strtolower($default), array('true','1'));
												break;
										}
									}
									
									// Append the parameter
									$params[$name] = array(
										'type' => $type,
										'desc' => $desc,
										'default' => $default,
										'strict' => $strict
									);
								}
							}
							elseif (trim(strtolower($r)) == 'content')
							{
								$content = trim($reg[2][$key]);
								if (strlen($content)==0) 
								{
									$content = true;
								}
							}
						}
						
						// Description parameters
						if (count($descParams = array_keys($params))>0)
						{
							array_walk(
								$descParams, 
								create_function(
									'&$str', 
									'$str = \'{\'.$str.\'}\';'
								)
							);
							$descParams = implode(' ', $descParams);
						}
						else 
						{
							$descParams = '';
						}
						
						// All done
						return array(
							'title'=>$title,
							'description'=>$description,
							'clean_description'=>$clean_description,
							'params'=>$params,
							'content'=>$content
						);
					}
					else 
					{
						// Bad comment!
						return false;
					}
				}
				
				function __construct() {
					// Get the current page
					global $pagenow;
					
					// Set the widget title
					$widgetTitle = sprintf(
						'* %s - %s',
						ucwords(str_replace('_', ' ', $this->widgetClassName)),
						ucwords(str_replace('_', ' ', $this->widgetClassMethod))
					);
					
					// Set the widget class
					$options['classname'] = sprintf(
						'wp_octoms_%s_%s',
						strtolower($this->widgetClassName),
						strtolower($this->widgetClassMethod)
					);
					
					// Extra data for the widget admin
					if ($pagenow == 'widgets.php')
					{
						if(false !== $data = $this->_getWidgetDetails())
						{
							if (!is_null($data['title'])) $widgetTitle = '* '.$data['title'];
							$options['description'] = $data['clean_description'].'&#8756;Shortcode ready. Powered by WP-OctoMS.';;
						}
					}
					else 
					{
						// Set the options
						$options['description'] = sprintf(
							'WP-OctoMS widget %s - %s',
							$this->widgetClassName,
							$this->widgetClassMethod
						);
					}
										
					// Instantiate the parent object
					parent::__construct(
						strtolower(
							'wp_octoms_'.$this->widgetClassName.'_'.$this->widgetClassMethod
						),
						$widgetTitle,
						$options,
						array(
							'width' => 400
						)
					);
				}
			
				function widget( $args, $instance ) {
					// Any additional widget class?					
					if (isset($instance['*class']) && !empty($instance['*class']))
					{
						$args['before_widget'] = str_replace(
							'class="', 
							'class="'.$instance['*class'].(isset($instance['*class2'])?($instance['*class2'].' '):''),
							$args['before_widget']
						);
					}
					unset($instance['*class']);
					unset($instance['*class2']);
					
					// Start the widget
					echo $args['before_widget'];
					
					// Title
					if (!empty($instance['*title']))
					{
						echo $args['before_title'] . apply_filters('widget_title', $instance['*title']) . $args['after_title'];
					}
							    
					// Remove the title
					unset($instance['*title']);
					
					// Get the content
					$content = isset($instance['*content'])?$instance['*content']:null;
					unset($instance['*content']);
					
					// Parse string commands
					foreach ($instance AS $key => $value)
					{
						if ($value === 'true') $instance[$key] = true;
						if ($value === 'false') $instance[$key] = false;
						if ($value === 'null' || $value === '') $instance[$key] = null;
						if (false !== strpos($value, '{') && false !== strpos($value, '}'))
						{
							if (null !== $json = @json_decode(str_replace('&quot;', '"', $value)))
							{
								$instance[$key] = (array)$json;
							}
						}
					}
					
					// Remove trailing nulls
					$keys = array_keys($instance);
					for ($i = count($instance); $i > 0; $i--){if (null===$instance[$keys[$i-1]]){unset($instance[$keys[$i-1]]);}else {break;}}
					
					// Call the widget
					if (count($instance)>0)
					{
						print octoms('template',OMS_L)->widget($this->widgetClassName,$this->widgetClassMethod,$instance,$content);
					}
					else 
					{
						print octoms('template',OMS_L)->widget($this->widgetClassName,$this->widgetClassMethod,null,$content);
					}
					
					// End
					echo $args['after_widget'];
				}
			
				function update($n,$o){
					// Get the widget details
					$data = $this->_getWidgetDetails();
					
					// Set the new instance
					if ($data['content'])
					{
						$i = array(
							'*title'=>$n['*title'],
							'*content'=>$n['*content'],
							'*class'=>$n['*class'],
							'*class2'=>$n['*class2']
						);
					}
					else 
					{
						$i = array(
							'*title'=>$n['*title'],
							'*class'=>$n['*class'],
							'*class2'=>$n['*class2']
						);
					}
					
					foreach ($data['params'] AS $name => $param)
					{
						// Not set?
						if (!isset($n[$name]))
						{
							if (in_array($param['type'],array('bool','boolean')))
							{
								$i[$name] = false;
							}
							else 
							{
								$i[$name] = '';
							}
						}
						else 
						{
							// Set the field
							$i[$name] = $n[$name];
							
							// Verify the bool
							if (in_array($param['type'],array('bool','boolean')))
							{
								$i[$name] = (bool)$n[$name];
							}
							// Verify the array
							elseif ($param['type'] == 'array')
							{
								// Try to fix encoding
								$value = str_replace('&quot;', '"', $n[$name]);
								if(null === @json_decode($value))
								{
									$i[$name] = '';
								}
								else 
								{
									$i[$name] = $value;
								}
							}
						}
					}
					return $i;
				}
			
				function form( $instance ) {
					if(false !== $data = $this->_getWidgetDetails())
					{
						// Prepare the fields
						if ($data['content'])
						{
							$fields = array(
								'*title'=>'',
								'*content'=>'',
								'*class'=>'',
								'*class2'=>''
							);
						}
						else 
						{
							$fields = array(
								'*title'=>'',
								'*class'=>'',
								'*class2'=>''
							);
						}
						
						foreach (array_keys($data['params']) AS $param)
						{
							if (in_array($data['params'][$param]['type'],array('bool','boolean')))
							{
								$fields[$param] = (bool)in_array($data['params'][$param]['default'], array('true','1'));
							}
							else
							{
								$fields[$param] = $data['params'][$param]['strict'] ? '' : $data['params'][$param]['default'];
							}
						}

						// Prepare the instance
						$instance = wp_parse_args((array)$instance,$fields);

						if (isset($instance['*title']))
						{
							// Print the description
							print sprintf(
								'<blockquote><i>%s</i></blockquote><br/>',
								$data['description']
							);
							
							// Print the title
							print '<p><label for="'.$this->get_field_id('*title').'">'.
							'<b>Widget title</b> (optional): <input class="widefat" id="'.$this->get_field_id('*title').'" name="'.$this->get_field_name('*title').'" type="text" value="'.esc_attr($instance['*title']).'" />'.
							'<span class="side-info">Set the widget\'s title.</span></label></p>';
							
							// Set a widget width?
							print '<p><label for="'.$this->get_field_id('*class').'"><b>Widget width</b> (optional):';
							$numbers = array(
								'one','two','three','four','five','six','seven','eight',
								'nine','ten','eleven','twelve','thirteen','fourteen','fifteen','sixteen'
							);
							$columns = array(''=>'Select widget width');
							foreach ($numbers AS $key => $nr) 
							{
								$columns[$nr.' columns '] = ($key+1) . ' column'.(($key+1)!=1?'s':'');
							}
							print select($columns,isset($instance['*class'])?$instance['*class']:'',$this->get_field_name('*class'),array('class'=>'widefat'));
							print '<span class="side-info">Set the width of the widget in this sidebar.</span></label></p>';
							
							// Optional classes?
							print '<p><label for="'.$this->get_field_id('*class2').'">'.
							'<b>Widget classes</b> (optional): <input class="widefat" id="'.$this->get_field_id('*class2').'" name="'.$this->get_field_name('*class2').'" type="text" value="'.esc_attr(isset($instance['*class2'])?$instance['*class2']:'').'" />'.
							'<span class="side-info">You may set extra widget classes such as \'alpha\' and \'omega\'(for the CSS grid).</span></label></p>';
							
							// Prepare the arguments
							$args = array();
							
							// Print the forms
							foreach ($data['params'] AS $name => $field)
							{
								if (isset($instance[$name]))
								{
									switch ($field['type'])
									{
										case 'bool':
										case 'boolean':
											$input = '<input id="'.$this->get_field_id($name).'" name="'.$this->get_field_name($name).'" type="checkbox" '.($instance[$name]?'checked="checked"':'').' />';
											$args[$name] = $instance[$name]?'true':'false';
											
											print '<p><label for="'.$this->get_field_id($name).'">'.$input.' '.$field['desc'].'</label></p>';
											break;
										default:
											// Use a list?
											if ($field['strict'] && $field['type'] != 'array')
											{
												$input = select($field['default'],$instance[$name],$this->get_field_name($name),array('class'=>'widefat'));
											}
											else 
											{
												$input = '<input '.(in_array($field['type'],array('int','float','numeric'))?'size="3"':'class="widefat"').' id="'.$this->get_field_id($name).'" name="'.$this->get_field_name($name).'" type="text" value="'.esc_attr($instance[$name]).'" />';
												
												if ($field['type'] == 'array')
												{
													// Strict?
													if ($field['strict'] && count($field['default'])>0)
													{
														$input .= '<span class="side-info">(Available key'.(count($field['default'])!=1?'s':'').': "'.implode('", "', $field['default']).'". Use '.a('JSON','http://json.org',array('target'=>'_blank')).'.)</span>';
													}
													else 
													{
														$input .= '<span class="side-info">(Use '.a('JSON','http://json.org',array('target'=>'_blank')).'.)</span>';
													}
												}
												else 
												{
													$input .= '<span class="side-info">('.$field['type'].')</span>';
												}
											}
											if (strlen($instance[$name])>0)
											{
												$args[$name] = trim($instance[$name]);
											}
											else 
											{
												$args[$name] = 'null';
											}
											
											print '<p><label for="'.$this->get_field_id($name).'">'.$field['desc'].': '.$input.'</label></p>';
											break;
									}
									
									
								}
							}
							
							// Print the optional content
							if ($data['content'])
							{
								print '<p><label for="'.$this->get_field_id('*content').'">'.
								'Content: <textarea class="widefat" id="'.$this->get_field_id('*content').'" name="'.$this->get_field_name('*content').'" style="resize:none;" rows=4>'.$instance['*content'].'</textarea>'.
								'<span class="side-info">String. ('.(is_string($data['content'])?$data['content']:'optional; sets the <b>__content</b> property in the widget controller').')</span></label></p>';
							}
							
							// Remove trailing nulls
							$args_keys = array_keys($args);
							for ($i = count($args_keys); $i > 0; $i--){if ('null'===$args[$args_keys[$i-1]]){unset($args[$args_keys[$i-1]]);}else {break;}}
							
							// Arguments for the shortcode
							$args1 = array();
							$args2 = array();
							foreach ($args AS $key => $value)
							{
								if (preg_match('%[^a-z0-9]%i', $value))
								{
									$args1[$key] = sprintf(
										'%s="%s"',
										$key,
										str_replace('"', '&amp;quot;', $value)
									);
									
									if (null !== @json_decode($value))
									{
										$args2[] = $value;
									}
									else 
									{
										$args2[] = sprintf(
											'"%s"',
											str_replace('"', '&amp;quot;', $value)
										);
									}
								}
								else 
								{
									if ($value !== 'null')
									{
										$args1[$key] = sprintf(
											'%s=%s',
											$key,
											$value
										);
									}
									$args2[] = $value;
								}
							}
							$args1 = implode(' ', $args1);
							$args2 = implode(' ', $args2);
							
							// Arguments for the template method
							foreach ($args AS $key => $value)
							{
								if ($value === 'true') $args[$key] = true;
								if ($value === 'false') $args[$key] = false;
								if ($value === 'null' || $value === '') $args[$key] = null;
								if (false !== strpos($value, '{') && false !== strpos($value, '}'))
								{
									if (null !== $json = @json_decode($value))
									{
										$args[$key] = (array)$json;
									}
								}
							}
							
							if ($data['content'])
							{
								// Content for the shortcode
								$sc = strlen($instance['*content'])>0?(htmlspecialchars($instance['*content'],ENT_QUOTES)):'';
								
								// Content for the widget
								$wc = strlen($instance['*content'])>0?sprintf(", '%s'",str_replace('\'', '\\\'', htmlspecialchars($instance['*content'],ENT_QUOTES))):'';
							}
							else 
							{
								$sc = '';
								$wc = '';
							}
							$sc .= '[/'.$this->widgetClassName.']';
							
							// Print the help
							print sprintf(
								'<hr/>
								&#8756;Shortcode (verbose): <span class="side-info">[%s %s%s]%s</span><br/><br/>
								&#8756;Shortcode (compact): <span class="side-info">[%s %s%s]%s</span><br/><br/>
								&#8756;Call this widget with <span class="side-info">octoms(\'template\',OMS_L)->widget(\'%s\', \'%s\'%s%s);</span> in your template files.<br/><br/>
								<b>&copy; Powered by <a href="http://octoms.com" target="_blank">WP-OctoMS</a></b>.',
								$this->widgetClassName,
								$this->widgetClassMethod,
								(strlen($args1)>0?' '.$args1:''),
								$sc,
								$this->widgetClassName,
								$this->widgetClassMethod,
								(strlen($args2)>0?' '.$args2:''),
								$sc,
								$this->widgetClassName,
								$this->widgetClassMethod,
								(count($args)>0?(', '.preg_replace('/\s*[0-9]+\s*=>\s*|,\s*(?=\))/i', '', var_export($args,true))):', null'),
								$wc
							);
						}
					}
					else 
					{
						print 'Invalid widget. Please remove method "'.$this->widgetClassMethod.'" from file "'.WIDGETS.DS.$this->widgetClassName.DS.'controllers'.DS.$this->widgetClassName.EXT.'".';
					}
				}
			}
			
			// Find all widgets
			if ( false !== $dir = @opendir( WIDGETS) ) {
				while (($class = readdir( $dir ) ) !== false ) 
				{
					if ( in_array($class, array('.', '..') ) )continue;
					if ( is_dir( WIDGETS . DS . $class )  && strpos($class, '_') !== 0) 
					{
						// Calculate the filename
						$f = WIDGETS.DS.$class.DS.'controllers'.DS.'w_'.$class.EXT;

						// Get the class
						if (file_exists($f))
						{
							// Load the class
							require_once $f;

							// Calculate the methods
							if (count($methods = get_class_methods('w_'.$class))>0)
							{
								foreach ($methods AS $method)
								{
									// Methods must not start with underscore
									if (strpos($method, '_') !== 0)
									{
										// Define the class name
										$className = 'WP_OctoMS_Widget_'.$class.'_'.$method;
										
										// Dynamically append the class
										forge(
											sprintf('class %s extends WP_OctoMS_Widget {var $widgetClassName = \'%s\';var $widgetClassMethod = \'%s\';}',
												$className,
												$class,
												$method
											)
										);
										
										// Initialize the widget
										add_action(
											'widgets_init',
											create_function(
												'', 
												sprintf(
													'register_widget(\'%s\');',
													$className
												)
											)
										);
									}
								}
							}
						}
					}
				}
			}
			@closedir( $dir );
		}
		
		// Add the WordPress Admin element
		function add_admin()
		{		
			// Add the page
			call_user_func('add_menu_page',
				// Page title
				WP_OCTOMS_TITLE,
				// Menu title
				WP_OCTOMS_TITLE, 
				// Capability
				'administrator',
				// Slug
				ADMINSLUG, 
				// Function
				'octoms_admin', 
				// Icon URL
				get_template_directory_uri().'/wp-favicon.png', 
				// Position
				61
			);
		}
	}
	
	// Called from everywhere WordPress was bootstrapped
	if (function_exists('add_action'))
	{
		// We need the (silent) OctoMS Framework for the public pages as well
		if (!(is_admin() && isset($_GET['page']) && $_GET['page'] == ADMINSLUG) && false === strpos($_SERVER['REQUEST_URI'],'functions.php'))
		{
			octoms_public();
		}

		// Have we just installed this theme?
		global $pagenow;
		if ( is_admin() && 'themes.php' == $pagenow && isset( $_GET['activated'] ) ) 
		{
			// Redirect to the Admin page
			header('location:'.admin_url( 'admin.php?page='.ADMINSLUG ));
			exit();
		}

		// Add the admin menu
		if (is_admin())
		{
			add_action('admin_menu', 'add_admin');
		}
		
		// Add the uninstall procedure
		add_action('switch_theme','wp_octoms_uninstall');
		
		// Register the sidebars
		if (count($sidebars = explode(',', WP_SIDEBARS))>0)
		{
			foreach ($sidebars AS $s)
			{
				register_sidebar(
					array(
						'name'=>trim(ucwords(strtolower(str_replace('_', ' ', $s)))),
						'id'=>'sidebar_'.trim(strtolower(str_replace(' ', '_', $s))),
						'before_widget' => '<div id="%1$s" class="widget %2$s">',
						'after_widget'  => '</div>'
					)
				);
			}
		}
		
		// Add theme support for menus
		add_theme_support( 'menus' );

		// Register the menus
		if (count($menus = explode(',', WP_MENUS))>0)
		{
			foreach ($menus AS $m)
			{
				register_nav_menu(
					$m,
					'The '.WP_OCTOMS_TITLE.' "'.ucwords(str_replace('_', ' ', $m)).'" menu.'
				);
			}
		}
		
		// Add theme support for post thumbnails
		add_theme_support( 'post-thumbnails' );
		add_theme_support( 'automatic-feed-links' );
		add_theme_support( 'custom-header' );
		add_theme_support( 'custom-background' );
		
		// Use these sometime
		if(false)
		{
			$content_width = 900;
			get_avatar();
			the_post_thumbnail();
			post_class();
			the_tags();
			posts_nav_link();
			add_editor_style();
			wp_enqueue_script("comment-reply");
			wp_list_comments();
			wp_link_pages();
			comments_template();
			comment_form();
			paginate_comments_links();
		}

	}
	// Called the /functions.php/ file directly - to display debugging info to the admin panel
	else 
	{
		octoms_admin();
	}
	
/* End Of File <functions.php> */